package com.example.ass7.dataloader;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.ass7.helper.Convertor;
import com.example.ass7.helper.StringUtil;

/**
 * @author Meirav Ben Izhak
 */
public class BlocksDefinitionReader {

    private static final String DEFAULT_KEY = "default";
    private static final String BDEF_KEY = "bdef";
    private static final String SDEF_KEY = "sdef";
    private static final String HEIGHT_KEY = "height";
    private static final String SYMBOL_KEY = "symbol";
    private static final String WIDTH_KEY = "width";
    private static final String HIT_POINTS_KEY = "hit_points";
    private static final String FILL_KEY = "fill";
    private static final String STROKE_KEY = "stroke";

    private final Map<String, String> defaultMap =
            new HashMap<String, String>();

    /**
     * @param reader
     *            reader
     * @return BlocksFromSymbolsFactory
     * @throws IOException
     *             IOException
     */
    public BlocksFromSymbolsFactory fromReader(java.io.Reader reader)
           throws IOException {
        BlocksFromSymbolsFactory fact = new BlocksFromSymbolsFactory();
        ColorsParser colorsParser = new ColorsParser();
        BufferedReader br = new BufferedReader(reader);
        while (br.ready()) {
            String line = br.readLine();
            if (line != null
                    && !line.isEmpty()) {

                line = StringUtil.trimAll(line);
                if (line.startsWith("#")) {
                    continue;
                }

                String[] pairs = line.split(" ");
                if (pairs != null
                        && pairs.length > 0) {

                    if (pairs[0].equals(DEFAULT_KEY)) {
                        for (int index = 1; index < pairs.length; index++) {
                            String[] pair = pairs[index].split(":");
                            if (pair != null
                                    && pair.length == 2) {
                                String key = pair[0].trim();
                                String value = pair[1].trim();
                                this.defaultMap.put(key,
                                        value);
                            }
                        }
                    } else if (pairs[0].equals(BDEF_KEY)) {
                        Map<String, String> map = this.getIntoPairMap(pairs);
                        String symbol = map.get(SYMBOL_KEY);
                        String height = this.getDefaultIfEmpty(map
                                .get(HEIGHT_KEY),
                                HEIGHT_KEY);
                        String width = this.getDefaultIfEmpty(map
                                .get(WIDTH_KEY),
                                WIDTH_KEY);
                        String hitPoints = this.getDefaultIfEmpty(map
                                .get(HIT_POINTS_KEY),
                                HIT_POINTS_KEY);
                        Background defaultFillColor = colorsParser
                                .colorFromString(this.getDefaultIfEmpty(map
                                        .get(FILL_KEY),
                                        FILL_KEY));
                        List<Background> fillColors = this
                                .getFillColorList(FILL_KEY,
                                        colorsParser,
                                        map,
                                        Convertor.parseInt(hitPoints),
                                        defaultFillColor);
                        Background strokeColor = colorsParser
                                .colorFromString(this.getDefaultIfEmpty(map
                                        .get(STROKE_KEY),
                                        STROKE_KEY));
                        BlockCreator blockCreator = new BlockCreatorImpl(
                                Convertor.parseDouble(height),
                                Convertor.parseDouble(width),
                                Convertor.parseInt(hitPoints),
                                defaultFillColor, fillColors, strokeColor);
                        fact.addBlockCreators(symbol,
                                blockCreator);
                    } else if (pairs[0].equals(SDEF_KEY)) {
                        Map<String, String> map = this.getIntoPairMap(pairs);
                        String symbol = map.get(SYMBOL_KEY);
                        String width = map.get(WIDTH_KEY);
                        fact.addSpacerWith(symbol,
                                Convertor.parseInt(width));
                    }
                }
            }
        }

        return fact;
    }

    /**
     * @param fillKey
     *            fillKey
     * @param colorsParser
     *            colorsParser
     * @param map
     *            map
     * @param hitPoints
     *            hitPoints
     * @param defaultFillColor
     *            defaultFillColor
     * @return List<Background>
     * @throws IOException
     *             IOException
     */
    private List<Background> getFillColorList(String fillKey,
            ColorsParser colorsParser,
            Map<String, String> map,
            int hitPoints,
            Background defaultFillColor) throws IOException {
        List<Background> colors = new ArrayList<Background>();
        for (int index = 1; index <= hitPoints; index++) {
            String fullKey = fillKey
                    + "-" + index;
            if (null != map.get(fullKey)) {
                Background color = colorsParser.colorFromString(map
                        .get(fullKey));
                colors.add(color);
            } else {
                colors.add(defaultFillColor);
            }
        }
        return colors;
    }

    /**
     * @param pairs
     *            pairs
     * @return Map<String, String>
     */
    private Map<String, String> getIntoPairMap(String[] pairs) {
        Map<String, String> map = new HashMap<String, String>();
        for (int index = 1; index < pairs.length; index++) {
            String[] pair = pairs[index].split(":");
            if (pair != null
                    && pair.length == 2) {
                String key = pair[0].trim();
                String value = pair[1].trim();
                map.put(key,
                        value);
            }
        }
        return map;
    }

    /**
     * @param apply
     *            apply
     * @param key
     *            key
     * @return String
     */
    private String getDefaultIfEmpty(String apply,
            String key) {
        if (apply == null
                || apply.isEmpty()) {
            return this.defaultMap.get(key);
        }
        return apply;
    }

}